#include "stdafx.h"
#include "ClientThreads.h"
#include "..\Common\CommonMessage.h"
#include "..\Common\CommonObject.h"


DWORD WINAPI BroadcastReceiverThread(LPVOID arg) {
	broadcast_thread_arg* BroadcastThreadArg =  (broadcast_thread_arg*)arg;	
	
	int RecvLen = 0;
	BRODCAST_MESSAGE Msg;	

	while(1) {			
		if(BroadcastThreadArg->PtrBroadcastNetwork->Recv((char*)&Msg, sizeof(Msg), &RecvLen) == false) {
			BroadcastThreadArg->PtrClient->Error(EC_INVALID_NETWORK);
			break;
		}

		switch(Msg) {
			case B_NEW_CLIENT: {
					broadcast_msg_NEW_CLIENT Data;
					if(BroadcastThreadArg->PtrBroadcastNetwork->Recv((char*)&Data, sizeof(broadcast_msg_NEW_CLIENT), &RecvLen) == false)
						BroadcastThreadArg->PtrClient->Error(EC_INVALID_NETWORK);		
					assert(RecvLen == sizeof(broadcast_msg_NEW_CLIENT));

					if(Data.ClientCode != BroadcastThreadArg->PtrClient->GetClientCode()) {
						BroadcastThreadArg->PtrObjectManager->AddClient(Data.IP, Data.ClientCode, Data.UdpPort);
						BroadcastThreadArg->PtrObjectManager->ConnectTargetClient(Data.IP, Data.UdpPort);
					}
					else
						BroadcastThreadArg->PtrObjectManager->ConnectOtherClients();

					if(BroadcastThreadArg->PtrClient->GetMoniterBroadcaster())
						BroadcastThreadArg->PtrCommander->Out(_T("[System][Broadcaster] New Client[%d]"), Data.ClientCode);

				}
				break;

			case B_OFF_CLIENT: {
					broadcast_msg_OFF_CLIENT Data;
					if(BroadcastThreadArg->PtrBroadcastNetwork->Recv((char*)&Data, sizeof(broadcast_msg_OFF_CLIENT), &RecvLen) == false)
						BroadcastThreadArg->PtrClient->Error(EC_INVALID_NETWORK);		
					assert(RecvLen == sizeof(broadcast_msg_OFF_CLIENT));
					BroadcastThreadArg->PtrObjectManager->DeleteClient(Data.ClientCode);

					if(BroadcastThreadArg->PtrClient->GetMoniterBroadcaster())
						BroadcastThreadArg->PtrCommander->Out(_T("[System][Broadcaster] Off Client[%d]"), Data.ClientCode);
				}
				break;

			case B_NEW_OBJECT: {
					broadcast_msg_NEW_OBJECT Data;
					if(BroadcastThreadArg->PtrBroadcastNetwork->Recv((char*)&Data, sizeof(broadcast_msg_NEW_OBJECT), &RecvLen) == false)
						BroadcastThreadArg->PtrClient->Error(EC_INVALID_NETWORK);		
					assert(RecvLen == sizeof(broadcast_msg_NEW_OBJECT));
					// recv extra data.
					Data.ExtraPtr = new char[Data.ExtraLength];
					if(BroadcastThreadArg->PtrBroadcastNetwork->Recv(Data.ExtraPtr, Data.ExtraLength, &RecvLen) == false)
						BroadcastThreadArg->PtrClient->Error(EC_INVALID_NETWORK);		
					assert(RecvLen == Data.ExtraLength);
					BroadcastThreadArg->PtrObjectManager->AddObject(Data.ObjectID, Data.ObjectType, Data.OwnerCode,
																	Data.ExtraLength, Data.ExtraPtr);
					delete [] Data.ExtraPtr;

					if(BroadcastThreadArg->PtrClient->GetMoniterBroadcaster())
						BroadcastThreadArg->PtrCommander->Out(_T("[System][Broadcaster] New Object[%d]"), Data.ObjectID);
				}
				break;

			case B_DEL_OBJECT: {
					static unsigned int BeforeDeleteObjectID = 0;

					broadcast_msg_DEL_OBJECT Data;
					if(BroadcastThreadArg->PtrBroadcastNetwork->Recv((char*)&Data, sizeof(broadcast_msg_DEL_OBJECT), &RecvLen) == false)
						BroadcastThreadArg->PtrClient->Error(EC_INVALID_NETWORK);		
					assert(RecvLen == sizeof(broadcast_msg_DEL_OBJECT));

					if(BeforeDeleteObjectID != Data.ObjectID)
						BroadcastThreadArg->PtrObjectManager->DeleteObject(Data.ObjectID);
					BeforeDeleteObjectID = Data.ObjectID;


					if(BroadcastThreadArg->PtrClient->GetMoniterBroadcaster())
						BroadcastThreadArg->PtrCommander->Out(_T("[System][Broadcaster] Delete Object[%d]"), Data.ObjectID);
				}
				break;

			case B_MISSILE_CRUSH: {
					broadcast_msg_MISSILE_CRUSH Data;

					if(BroadcastThreadArg->PtrBroadcastNetwork->Recv((char*)&Data, sizeof(broadcast_msg_MISSILE_CRUSH), &RecvLen) == false)
						BroadcastThreadArg->PtrClient->Error(EC_INVALID_NETWORK);		
					assert(RecvLen == sizeof(broadcast_msg_MISSILE_CRUSH));
					BroadcastThreadArg->PtrCommander->Out(_T("[Broadcast] %d's Missile %d crush %d Ship."), 
						Data.MissileOwner, Data.MissileId, Data.TargetClient);
				}
				break;

			case B_MESSAGE: {
					broadcast_msg_MESSAGE Data;
					if(BroadcastThreadArg->PtrBroadcastNetwork->Recv((char*)&Data, sizeof(broadcast_msg_MESSAGE), &RecvLen) == false)
							BroadcastThreadArg->PtrClient->Error(EC_INVALID_NETWORK);	
					assert(RecvLen == sizeof(broadcast_msg_MESSAGE));
					// recv extra data
					Data.MsgString = new char[Data.MsgLength];
					if(BroadcastThreadArg->PtrBroadcastNetwork->Recv(Data.MsgString, Data.MsgLength, &RecvLen) == false)
							BroadcastThreadArg->PtrClient->Error(EC_INVALID_NETWORK);	
					assert(RecvLen == Data.MsgLength);
					BroadcastThreadArg->PtrCommander->Out(_T("%s"), (wchar_t*)Data.MsgString); 
					delete [] Data.MsgString;
				}
				break;

			case B_CHECK_SOCKET:
				if(BroadcastThreadArg->PtrClient->GetMoniterBroadcaster())
						BroadcastThreadArg->PtrCommander->Out(_T("[System][Broadcaster] Check Socket"));
				// non  work. 
				break;

			// add code point. at new brodcast message.
		}		
	}

	delete BroadcastThreadArg;

	return NULL;
}

DWORD WINAPI MotionUpdateThread(LPVOID arg) {
	motion_update_threade_arg* MotionThreadArg = (motion_update_threade_arg*)arg;	
	
	char	Buffer[MAX_SYNC_LENGTH];
	int		RecvLen;

	while(1) {
		if(MotionThreadArg->PtrUDPNetwork->RecvUDP(Buffer, sizeof(Buffer), &RecvLen, NULL, NULL) == false) {
			Sleep(10);
			continue;
		}
		
		if(RecvLen == sizeof(sync_object_3d)) {
			MotionThreadArg->PtrObjectManager->UpdateOtherClientObject((sync_object_3d*)Buffer);
		}
		else if(RecvLen == sizeof(sync_link)) {
			MotionThreadArg->PtrObjectManager->TryUdpLink(((sync_link*)Buffer)->ClienetCode);			
		}
	}

	delete MotionThreadArg;
	return NULL;
}

DWORD WINAPI UdpLinkThread(LPVOID arg) {
	udp_link_thread_arg* UdpLinkThreadArg = (udp_link_thread_arg*)arg;

	sync_link SendData;
	
	SendData.SyncType		= ST_LINK_UDP;
	SendData.ClienetCode	= UdpLinkThreadArg->MyClientCode;	
	SendData.TotalCount		= 0;

	ip		TargetIP;
	TargetIP.s_addr = inet_addr(UdpLinkThreadArg->TargetIP.c_str());
	port	TargetPort	= ntohs(UdpLinkThreadArg->TargetPort);
	
	for(int Repeat = 0; Repeat < 60; ++Repeat) {
		for(int Send = 0; Send < 100; ++Send) {
			UdpLinkThreadArg->PtrUDPNetwork->SendUDP((char*)&SendData, sizeof(SendData), 
									TargetIP, TargetPort);
			++(SendData.TotalCount);
		}	
		
		Sleep(0.03333); // this thread work 2 sec
	}

	delete UdpLinkThreadArg;
	return NULL;

}